package org.com.gr.capserver.utils;

import com.mongodb.client.result.UpdateResult;
import org.apache.commons.lang3.StringUtils;
import org.bson.types.ObjectId;
import org.com.gr.capserver.model.enums.SortEnum;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;


@Component
public class MongoHelper {
    @Autowired
    private MongoTemplate mongoTemplate;



    /**
     * 传入什么则返回什么类型分页对象
     * @param current   当前页
     * @param size      每页大小
     * @param query     spring针对mongo封装的查询对象
     * @param tClass    传入的class
     * @param <T>       泛型
     * @param orderName  排序字段名称
     * @param sort  排序方式 SortEnum  1升序 ，2降序
     * @return
     */
    public <T> Page<T> getPage(int current,int size,Query query,Class<T> tClass,String orderName,int sort){

                MongoSpringPageable pageable = new MongoSpringPageable();
                // 开始页
                pageable.setPagenumber(current);
                // 每页条数
                pageable.setPagesize(size);
                // 排序
                switch (SortEnum.getByType(sort)) {
                    case DESC:
                        pageable.setSort(Sort.by(Sort.Order.desc(orderName)));
                        break;
                    case ASC:
                        pageable.setSort(Sort.by(Sort.Order.asc(orderName)));
                        break;
                    default:
                        pageable.setSort(Sort.by(Sort.Order.asc(orderName)));
                }
                // 查询出一共的条数
                long count = mongoTemplate.count(query, tClass);
                // 查询
                List<T> list = mongoTemplate.find(query.with(pageable),tClass);
                // 将集合与分页结果封装
                Page<T> pagelist = new PageImpl<T>(list, pageable, count);
                return pagelist;
    }
    public <T> Page<T> getPage(int current,int size,Query query,Class<T> tClass,Map<String,Integer> sort){

        MongoSpringPageable pageable = new MongoSpringPageable();
        // 开始页
        pageable.setPagenumber(current);
        // 每页条数
        pageable.setPagesize(size);
        // 排序
        if (!sort.isEmpty()){
            List<Sort.Order> list=new ArrayList<>();
            sort.entrySet().stream().forEach(sortOne->{
                switch (SortEnum.getByType(sortOne.getValue())) {
                    case DESC:
                        list.add(Sort.Order.desc(sortOne.getKey()));
                        break;
                    case ASC:
                        list.add(Sort.Order.asc(sortOne.getKey()));
                        break;
                    default:
                        list.add(Sort.Order.asc(sortOne.getKey()));
                }
            });
            pageable.setSort(Sort.by(list));
        }

        // 查询出一共的条数
        long count = mongoTemplate.count(query, tClass);
        // 查询
        List<T> list = mongoTemplate.find(query.with(pageable),tClass);
        // 将集合与分页结果封装
        Page<T> pagelist = new PageImpl<T>(list, pageable, count);
        return pagelist;
    }


    /**
     * @Description: 封装like查询条件
     * @Author: xiaofeng
     * @Date: 2022/09/03
     **/
    public Criteria queyrLike(String key ,String value){
        String search = ".*" + value + ".*";
        Pattern pattern = Pattern.compile(search, Pattern.CASE_INSENSITIVE);
        Criteria criteria =Criteria.where(key).regex(pattern);
        return criteria;
    }


    /**
     * @Description: 查询时间区段数据 查询条件封装
     * @Author: xiaofeng
     * @Date: 2022/09/09
     **/
    public Criteria findIntervalDate(String key,String startTime,String endTime){
        Criteria criteria = new Criteria();
        if (!StringUtils.isBlank(startTime) && !StringUtils.isBlank(endTime)){
            //开始 -- 结束时间 查询
            criteria = criteria.and(key);
            criteria.gte(startTime);
            criteria.lte(endTime);
            return criteria;
        } else if (!StringUtils.isBlank(startTime)) {
            //开始时间 查询
            criteria = criteria.and(key);
            criteria.gte(startTime);
            return criteria;
        } else if (!StringUtils.isBlank(endTime)) {
            //结束时间验证 查询
            criteria = criteria.and(key);
            criteria.lte(endTime);
            return criteria;
        }
        return criteria;
    }
    /**
     * 根据指定条件查询
     *
     * @param clazz      数据对象
     * @param map      Map<"查询条件key"，查询条件值> map
     * @param collName 集合名称
     * @return
     */
    public <T> Page<T> findByParamByPage(Class<T> clazz, String collName, Map<String, Object> map,int pageSize,int pageNumber,String orderName,int sort) {
        MongoSpringPageable pageable = new MongoSpringPageable();
        // 开始页
        pageable.setPagenumber(pageNumber);
        // 每页条数
        pageable.setPagesize(pageSize);
        // 排序
        switch (SortEnum.getByType(sort)) {
            case DESC:
                pageable.setSort(Sort.by(Sort.Order.desc(orderName)));
                break;
            case ASC:
                pageable.setSort(Sort.by(Sort.Order.asc(orderName)));
                break;
            default:
                pageable.setSort(Sort.by(Sort.Order.asc(orderName)));
        }
        if (map.containsKey(null)) {
            return null;
        }
        Criteria criteria = null;
        criteria = getCriteria(criteria, map);
        Query query = new Query();
        if (criteria != null) {
            query.addCriteria(criteria);
        }
        // 查询出一共的条数
        long count = mongoTemplate.count(query, clazz,collName);
        // 查询
        List<T> list = mongoTemplate.find(query.with(pageable),clazz,collName);
        Page<T> pagelist = new PageImpl<T>(list, pageable, count);
        return pagelist;
    }
    /**
     * 根据指定条件查询
     *
     * @param clazz      数据对象
     * @param map      Map<"查询条件key"，查询条件值> map
     * @param collName 集合名称
     * @return
     */
    public <T> List<T> findByParam(Class<T> clazz, String collName, Map<String, Object> map) {
        if (map.containsKey(null)) {
            return new ArrayList<>();
        }
        Criteria criteria = null;
        criteria = getCriteria(criteria, map);
        if (criteria == null) {
            return new ArrayList<>();
        }
        Query query = Query.query(criteria);
        if(!StringUtils.isEmpty(collName)){
            return mongoTemplate.find(query, clazz, collName);
        }
        return mongoTemplate.find(query, clazz);
    }
    public <T> T findOneByParam(Class<T> clazz, String collName, Map<String, Object> map) {
        if (map.containsKey(null)) {
            return null;
        }
        Criteria criteria = null;
        criteria = getCriteria(criteria, map);
        if (criteria == null) {
            return null;
        }
        Query query = Query.query(criteria);
        if(!StringUtils.isEmpty(collName)){
            return mongoTemplate.findOne(query, clazz, collName);
        }
        return mongoTemplate.findOne(query, clazz);
    }
    public <T> List<T> findByParam(Class<T> clazz, String collName, Map<String, Object> map,String orderName,int sort) {
        if (map.containsKey(null)) {
            return new ArrayList<>();
        }
        Criteria criteria = null;
        criteria = getCriteria(criteria, map);
        if (criteria == null) {
            return new ArrayList<>();
        }
        Query query = Query.query(criteria);
        if (!StringUtils.isEmpty(orderName)){
            switch (SortEnum.getByType(sort)){
                case DESC:
                        query.with( Sort.by(Sort.Order.desc(orderName)));
                        break;
                case ASC:
                        query.with(Sort.by(Sort.Order.asc(orderName)));
                        break;
                default:
                    query.with(Sort.by(Sort.Order.asc(orderName)));
            }

        }
        if(!StringUtils.isEmpty(collName)){
            return mongoTemplate.find(query, clazz, collName);
        }
        return mongoTemplate.find(query, clazz);
    }
    public long findCountByParam(String collName, Map<String, Object> map) {
        if (map.containsKey(null)) {
            return 0;
        }
        Criteria criteria = null;
        criteria = getCriteria(criteria, map);
        if (criteria == null) {
            return 0;
        }
        Query query = Query.query(criteria);
        return mongoTemplate.count(query, collName);
    }
    /**
     * 根据id 更新对象中的内容
     * @param clazz
     * @param collName
     * @param _id
     * @param map
     * @return
     */
    public boolean updateFirstById(Class clazz, String collName,String _id, Map<String, Object> map){
        Query query = new Query();
        query.addCriteria(Criteria.where("_id").is(new ObjectId(_id)));
        Update update= getUpdateSet(map);
        UpdateResult updateResult=null;
        if (StringUtils.isEmpty(collName)){
            updateResult= mongoTemplate.updateFirst(query, update, clazz);
        }else {
            updateResult= mongoTemplate.updateFirst(query, update, clazz,collName);
        }
        return updateResult.wasAcknowledged();

    }
    public <T> T findAndUpdateFirstById(Class<T> clazz, String collName,String _id, Map<String, Object> map){
        Query query = new Query();
        query.addCriteria(Criteria.where("_id").is(new ObjectId(_id)));
        Update update= getUpdateSet(map);
        T obj= mongoTemplate.findAndModify(query, update, clazz,collName);
        return obj;

    }
    public boolean updateFirstByKey(Class clazz, String collName,String KeyName,String KeyValue, Map<String, Object> map){
        Query query = new Query();
        query.addCriteria(Criteria.where(KeyName).is(KeyValue));
        Update update= getUpdateSet(map);
        UpdateResult updateResult=null;
        if (StringUtils.isEmpty(collName)){
             updateResult= mongoTemplate.updateFirst(query, update, clazz);
        }else {
            updateResult= mongoTemplate.updateFirst(query, update, clazz,collName);
        }
        return updateResult.wasAcknowledged();

    }
    /**
     * 根据指定key 和value到指定collName集合中删除数据
     *
     * @param key
     * @param value
     * @param collName
     */
    public  void removeAllByParam(String key, String value, String collName) {
        Criteria criteria = Criteria.where(key).is(value);
        Query query = Query.query(criteria);
        mongoTemplate.remove(query, collName);
    }
    public void removeAllByParamList(String key,List<? extends Object> list,String collName){
        Query query = new Query(new Criteria(key).in(list));
        mongoTemplate.remove(query, collName);
    }
    public <T> List<T> getDataByParamList(String key,List<String> list,Class<T> clazz,String collName){
        Query query = new Query(new Criteria(key).in(list));
        return mongoTemplate.find(query,clazz,collName);
    }
    public Update getUpdateSet(Map<String, Object> map) {
        Update update=new Update();
        map.entrySet().stream().filter(entry->{
                    return !entry.getKey().equals(FieldU.fName(PageVo::getPageIndex)) &&
                            !entry.getKey().equals(FieldU.fName(PageVo::getPageSize)) &&
                            !entry.getKey().equals("id") &&
                            !entry.getKey().equals("_id");
                }
        ).forEach(param->{
            update.set(param.getKey(),param.getValue());
        });
        return update;
    }

    /**
     *
     * @param criteria
     * @param map
     * @return
     */
    public  Criteria getCriteria(Criteria criteria, Map<String, Object> map) {
        if (map == null) {
            return null;
        }
        int i = 0;
        for (String key : map.keySet()) {
            if(FieldU.fName(PageVo::getPageIndex).equals(key)||FieldU.fName(PageVo::getPageSize).equals(key)
                ){
                continue;
            }
            if (i == 0) {
                criteria = Criteria.where(key).is(map.get(key));
                i++;
            } else {
                criteria.and(key).is(map.get(key));
            }
        }
        return criteria;
    }


    public Query getQuery(Map<String, Object> queryMap) {
        Query query=new Query();
        Criteria criteria=new Criteria();
        queryMap.entrySet().stream().forEach(entry -> {
            criteria.and(entry.getKey()).is(entry.getValue());
        });
        query.addCriteria(criteria);
        return query;
    }
}
